package org.koon.jadelyre;

import org.jadelyre.utils.ByteBufferUtils;
import org.jadelyre.utils.StrUtils;
import org.koon.KooRequest;
import org.koon.KoonFile;

import java.io.*;
import java.nio.ByteBuffer;
import java.util.HashMap;

public class MultiBodyDecoder {

    enum Step{
        BOUNDARY, HEADER, BODY, END
    }
    public static void decode(ByteBuffer byteBuffer, String boundary, KooRequest httpRequest) {
        boundary = "--" + boundary;
        String endBoundary = boundary + "--";
        Step step = Step.BOUNDARY;
        w1:while (true){
            if (step ==Step.BOUNDARY){
                String readLine = ByteBufferUtils.readLine(byteBuffer, httpRequest.getCharset());
                if (boundary.equals(readLine)){
                    step = Step.HEADER;
                }else {
                    break;
                }
            }
            KoonFile.Header header = null;
            if (step == Step.HEADER){
                header = decodeMultiBodyHeader(byteBuffer, httpRequest);
                step = Step.BODY;
            }
            if (step == Step.BODY){
                int initPosition = byteBuffer.position();
                w2:while (byteBuffer.hasRemaining()){
                    String line = ByteBufferUtils.readLine(byteBuffer, httpRequest.getCharset());
                    boolean isEndBoundary = endBoundary.equals(line);
                    boolean isBoundary = boundary.equals(line);
                    if (isBoundary || isEndBoundary) {
                        int startIndex = initPosition;
                        int endIndex = byteBuffer.position() - line.getBytes().length - 2 - 2;
                        int length = endIndex - startIndex;
                        byte[] dst = new byte[length];

                        System.arraycopy(byteBuffer.array(), startIndex, dst, 0, length);
                        String filename = header.getFilename();
                        if (filename != null){//该字段类型是file
                            KoonFile koonFile = new KoonFile();
                            koonFile.setFileName(filename);
                            koonFile.setName(header.getName());
                            koonFile.setData(dst);
                            koonFile.setSize(dst.length);
                            httpRequest.addKoonFile(koonFile);
                        } else {
                            try {
                                httpRequest.addParam(header.getName(), new String(dst, httpRequest.getCharset()));
                            } catch (UnsupportedEncodingException e) {
                                e.printStackTrace();
                            }
                        }
                        if (isEndBoundary) {
                            step = Step.END;
                        } else {
                            step = Step.HEADER;
                        }
                        break w2;
                    }
                }
                if (step ==Step.END){
                    break w1;
                }
            }
        }
    }


    private static KoonFile.Header decodeMultiBodyHeader(ByteBuffer byteBuffer, KooRequest httpRequest){
        KoonFile.Header header = new KoonFile.Header();
        for (int i = 0; i < 3; i++) {
            String line = ByteBufferUtils.readLine(byteBuffer, httpRequest.getCharset());
            if (StrUtils.isBlank(line)){
                break;
            }
            String[] split = line.split(":");
            header.getMap().put(split[0].trim().toLowerCase(),split[1].trim());
        }
        String contentDisposition = header.getMap().get(KoonFile.Header.Content_Disposition);
        String name = KoonEnde.extractValueFromEqPair(contentDisposition, "name");
        String filename = KoonEnde.extractValueFromEqPair(contentDisposition, "filename");
        String contentType = header.getMap().get(KoonFile.Header.Content_Type);
        header.setContentDisposition(contentDisposition);
        header.setName(name);
        header.setFilename(filename);
        header.setContentType(contentType);
        return header;
    }
}
